package com.guaigen.train.generator.util;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DbUtil {
    public static String url = "";
    public static String user = "";
    public static String password = "";

    /**
     * 获取数据库连接
     *
     * @return 数据库连接对象
     * @throws RuntimeException 如果驱动类找不到或数据库连接失败，则抛出运行时异常
     */
    public static Connection getConnection() {
        Connection connection = null;
        try {
            // 加载 MySQL JDBC 驱动类
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 从 DbUtil 类中获取数据库连接 URL、用户名和密码
            String url = DbUtil.url;
            String user = DbUtil.user;
            String password = DbUtil.password;
            // 建立数据库连接
            connection = DriverManager.getConnection(url, user, password);
        } catch (ClassNotFoundException | SQLException e) {
            // 如果发生 ClassNotFoundException 或 SQLException，则抛出运行时异常
            throw new RuntimeException(e);
        }
        return connection;
    }

    /**
     * 根据表名获取表注释
     *
     * @param tableName 表名
     * @return 表注释
     * @throws SQLException 如果查询过程中出现数据库访问错误
     */
    public static String getTableComment(String tableName) throws SQLException {
        // 获取数据库连接
        Connection connection = getConnection();
        // 创建Statement对象，用于执行SQL查询
        Statement st = connection.createStatement();
        // 执行SQL查询，获取表注释
        ResultSet rs = st.executeQuery("select table_comment from information_schema.tables where table_name = '" + tableName + "'");
        // 初始化表注释变量
        String tableNameCH = "";
        // 检查ResultSet是否为空
        if (rs != null) {
            // 遍历查询结果，获取表注释
            while (rs.next()) {
                tableNameCH = rs.getString("table_comment");
                break;
            }
        }
        // 确保ResultSet不为空，准备关闭
        assert rs != null;
        // 关闭ResultSet
        rs.close();
        // 关闭Statement
        st.close();
        // 关闭数据库连接
        connection.close();
        // 打印表注释
        System.out.println("表名：" + tableNameCH);
        // 返回表注释
        return tableNameCH;
    }

    /**
     * 根据表名获取列信息
     *
     * @param tableName 表名
     * @return 包含列信息的List<Field>
     * @throws SQLException 如果查询操作失败
     */
    public static List<Field> geColumByTableName(String tableName) throws SQLException {
        List<Field> fields = new ArrayList<>();
        Connection connection = getConnection();
        Statement st = connection.createStatement();
        ResultSet rs = st.executeQuery("show full columns from `" + tableName + "`");
        if (rs != null) {
            while (rs.next()) {
                String columName = rs.getString("Field");
                String type = rs.getString("Type");
                String comment = rs.getString("Comment");
                String nullAble = rs.getString("Null"); //YES NO
                Field field = new Field();
                field.setName(columName);
                field.setNameHump(lineToHump(columName));
                field.setNameBigHump(lineToBigHump(columName));
                field.setType(type);
                field.setJavaType(sqlTypeToJavaType(rs.getString("Type")));
                field.setComment(comment);
                if (comment.contains("|")) {
                    field.setNameCn(comment.substring(0, comment.indexOf("|")));
                } else {
                    field.setNameCn(comment);
                }
                field.setNullAble("YES".equals(nullAble));
                if (type.toUpperCase().contains("varchar".toUpperCase())) {
                    String lengthStr = type.substring(type.indexOf("(") + 1, type.length() - 1);
                    field.setLength(Integer.valueOf(lengthStr));
                } else {
                    field.setLength(0);
                }
                if (comment.contains("枚举")) {
                    field.setEnums(true);

                    int start = comment.indexOf("[");
                    int end = comment.indexOf("]");
                    String enumsName = comment.substring(start + 1, end);
                    String enumsConst = StrUtil.toUnderlineCase(enumsName).toUpperCase().replace("_ENUM", "");
                    field.setEnumsConst(enumsConst);
                } else {
                    field.setEnums(false);
                }
                fields.add(field);
            }
        }
        assert rs != null;
        rs.close();
        st.close();
        connection.close();
        System.out.println("列信息：" + JSONUtil.toJsonPrettyStr(fields));
        return fields;
    }

    /**
     * 将下划线命名的字符串转换为驼峰命名法
     *
     * @param columnName 带有下划线的字符串，例如 "user_name"
     * @return 转换为驼峰命名法的字符串，例如 "userName"
     */
    private static String lineToHump(String columnName) {
        // 编译正则表达式，用于匹配下划线后面的第一个字符
        Pattern linePattern = Pattern.compile("_(\\w)");
        // 将输入的字符串转换为小写，以确保转换过程中的一致性
        columnName = columnName.toLowerCase();
        // 创建一个匹配器，用于查找字符串中与正则表达式匹配的部分
        Matcher matcher = linePattern.matcher(columnName);
        // 使用StringBuilder来构建最终的驼峰命名字符串
        StringBuilder sb = new StringBuilder();
        // 遍历所有匹配的部分，将它们转换为大写并添加到StringBuilder中
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
        }
        // 将源字符串中剩余的部分添加到StringBuilder的末尾
        matcher.appendTail(sb);
        // 返回构建好的驼峰命名字符串
        return sb.toString();
    }

    /**
     * 将下划线命名的列名转换为大驼峰命名
     * @param columnName 下划线命名的列名
     * @return 大驼峰命名的字符串
     */
    private static String lineToBigHump(String columnName) {
        // 首先将下划线命名转换为小驼峰命名
        columnName = lineToHump(columnName);
        // 然后将首字母转换为大写，完成大驼峰命名的转换
        return columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
    }

    /**
     * 将SQL类型转换为Java类型
     * 根据SQL类型的名称，返回对应的Java类型字符串
     *
     * @param sqlType SQL类型的名称
     * @return 对应的Java类型字符串
     */
    private static String sqlTypeToJavaType(String sqlType) {
        // 检查SQL类型是否包含字符类型关键字，如果是，则返回Java中的String类型
        if (sqlType.toUpperCase().contains("varchar".toUpperCase())
                || sqlType.toUpperCase().contains("char".toUpperCase())
                || sqlType.toUpperCase().contains("text".toUpperCase())) {
            return "String";
        } else if (sqlType.toUpperCase().contains("datetime".toUpperCase())
                || sqlType.toUpperCase().contains("time".toUpperCase())
                || sqlType.toUpperCase().contains("date".toUpperCase())) {
            // 检查SQL类型是否包含日期时间类型关键字，如果是，则返回Java中的Date类型
            return "Date";
        } else if (sqlType.toUpperCase().contains("bigint".toUpperCase())
                || sqlType.toUpperCase().contains("long".toUpperCase())) {
            // 检查SQL类型是否包含长整型关键字，如果是，则返回Java中的Long类型
            return "Long";
        } else if (sqlType.toUpperCase().contains("int".toUpperCase())) {
            // 检查SQL类型是否包含整型关键字，如果是，则返回Java中的Integer类型
            return "Integer";
        } else if (sqlType.toUpperCase().contains("decimal".toUpperCase())) {
            // 检查SQL类型是否包含十进制关键字，如果是，则返回Java中的BigDecimal类型
            return "BigDecimal";
        } else if (sqlType.toUpperCase().contains("boolean".toUpperCase())) {
            // 检查SQL类型是否包含布尔类型关键字，如果是，则返回Java中的Boolean类型
            return "Boolean";
        } else {
            // 如果无法识别SQL类型，则默认返回Java中的String类型
            return "String";
        }
    }
}
